Some personal and computational notes loosely based on the analytical work I have done in response to COVID-19 pandemic in Scotland. In my GIS Analyst role I use wide range of proprietary and open source GIS software as well as tend to blend R and Python languages. Here is a flavor of my work in open and reproducible notebook, following a Donald Knuth’s “literate programming” paradigm.

Packages

First,all packages necessary for the analysis.

library(dplyr)
library(tidyr)
library(lubridate)
library(readr)
library(ggplot2)
library(rvest)
library(sf)
library(stringr)
library(tmap)
library(kableExtra)
library(gghighlight)
library(hrbrthemes)
library(gganimate) # animate plots
library(geofacet)
library(zoo) # moving avarages

Data Wrangling

Now, lets read the data from the Data Science Scotland repository

cases_scot = read_csv("https://raw.githubusercontent.com/DataScienceScotland/COVID-19-Management-Information/master/COVID19%20-%20Daily%20Management%20Information%20-%20Scotland%20-%20Testing.csv") %>% 
  select(Date,'Testing - Cumulative people tested for COVID-19 - Positive') %>% 
  rename(total = 'Testing - Cumulative people tested for COVID-19 - Positive') %>% 
  mutate(date = as.Date(Date, "%d-%b-%Y"))
  

# deaths 
deaths_scot = read_csv("https://raw.githubusercontent.com/DataScienceScotland/COVID-19-Management-Information/master/COVID19%20-%20Daily%20Management%20Information%20-%20Scotland%20-%20Deaths.csv") %>% 
    rename(total = 'Number of COVID-19 confirmed deaths registered to date') %>% 
    mutate(date = as.Date(Date, "%d-%b-%Y"))

Since we only have on variable with total cases and deaths, we are going to calculate additional attributes: daily new cases, percentage change and seven days rolling average.

#cases 
cases_scot  = cases_scot  %>% 
mutate(new_cases = (total - lag(total)), # new daily cases 
       pct_change = new_cases / lag(total) * 100, # percentage change
       cases_07da = rollmean(new_cases, k = 7, fill = NA)) # 7 days rolling average



# deaths
deaths_scot  = deaths_scot  %>% 
mutate(new_deaths = (total - lag(total)), # new daily cases 
      pct_change = new_deaths / lag(total) * 100, # percentage change
      deaths_07da = rollmean(new_deaths, k = 7, fill = NA)) # 7 days rolling average

Plotting

We are ready to plot our variables using ggplot package

ggplot()+
  geom_line(data = cases_scot, aes(x=Date, y=new_cases), color='gray') +
  geom_line(data = cases_scot, aes(x=Date, y=cases_07da), color='#ba0000') +
  labs( title = "Scotland's 7 days rolling average COVID-19 cases",
        subtitle = "Between March 2020 and March 2021", 
        caption="Source:https://github.com/DataScienceScotland/COVID-19-Management-Information ",
        y = "Cases", 
        x = "Month") +
  scale_x_date(date_breaks = '1 month', date_labels = '%m %y') +
  scale_y_log10() +
  hrbrthemes::theme_ipsum()

Mapping

We can also create a map showing latest cases at NHS Health Board level. But first we need to get the data for each geograph unit.

# load data
cases_by_hb = read_csv("https://raw.githubusercontent.com/DataScienceScotland/COVID-19-Management-Information/master/COVID19%20-%20Daily%20Management%20Information%20-%20Scottish%20Health%20Boards%20-%20Cumulative%20cases.csv")

# pivot data to long format nd select latest date
last_cases_by_hb_long = cases_by_hb %>%
pivot_longer(!Date,names_to = "hb_name", values_to = "cases")  %>%
mutate(cases = as.numeric(cases)) %>% 
filter(Date == max(Date))

# load mid 2019 population estimatie
pop_hb = read_csv("data/hb_pop_2019.csv")

# first join: cases with population, also calculate rate per 100k
cases_by_hb_pop = left_join(last_cases_by_hb_long, pop_hb) %>% 
  mutate(
    rate_100k = cases / hb_pop * 100000
  )

# load Health Board geographies
health_boards = st_read("data/SG_NHS_HealthBoards_2019.shp", quiet = TRUE)

# second join: health board boundaries 
cases_hb_rate100k = left_join(health_boards,cases_by_hb_pop, by = c("HBCode" = "hb_code"))

Finally, we are ready to produce the map using tmap package. Note that we are saving the output to png file.

map = tm_shape(cases_hb_rate100k) +
  tm_polygons(col = "rate_100k",
              title = "Data from 17th March 2021 \nNumber of confirmed cases per 100,000 people",
              lwd = 1,
              border.col = "white",
              style = "equal",
              n = 5,
              palette="cividis" # choose between reds or cividis
             # legend.format=list(fun=function(x) paste0(formatC(x, digits=0, format="f")))
              ) +
  tm_layout(
           # fontfamily = "arial",
            title = "Total COVID - 19 cases \nper 100,000 people, by NHS Health Board",
            title.size = 0.9,
            legend.title.size = 1,
            attr.outside= TRUE,
            attr.outside.position = "bottom",
            attr.outside.size = .1,
            attr.just = c("left", "top"),
            inner.margins = 0.02,
            outer.margins = c(0,0.01,0.01,0.01),
            asp = 4/6,
            frame = F,
            design.mode = F
           ) +
  tm_credits("Cases data from: https://www.gov.scot/coronavirus-covid-19\nPopulation data: NRS Population Estimates, mid-2018\nBoundaries: SpatialData.gov.scot",
             col = "grey50",
             position=c("left","top"), 
             align = "left",
             size = 0.325)
# save graphic to png file
tmap_save(
  tm = map,
  filename = "hb_map_cases_rate.png",
  height = 6,
  width = 4,
  units = "in",
  asp = 4/6
)
## Map saved to /Users/michal/Documents/covid/hb_map_cases_rate.png
## Resolution: 1200 by 1800 pixels
## Size: 4 by 6 inches (300 dpi)

Ok, map is ready !

I can’t recommend tmap package enough.

Session info

sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Mojave 10.14.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] zoo_1.8-9          geofacet_0.1.10    gganimate_1.0.5    hrbrthemes_0.8.0  
##  [5] gghighlight_0.3.0  kableExtra_1.3.4   tmap_3.0           stringr_1.4.0.9000
##  [9] sf_0.9-6           rvest_0.3.5        xml2_1.3.2         ggplot2_3.3.2     
## [13] readr_1.4.0        lubridate_1.7.9.2  tidyr_1.1.2        dplyr_1.0.2       
## 
## loaded via a namespace (and not attached):
##  [1] webshot_0.5.2       RColorBrewer_1.1-2  progress_1.2.2     
##  [4] httr_1.4.2          tools_4.0.2         R6_2.5.0           
##  [7] KernSmooth_2.23-17  rgeos_0.5-2         DBI_1.1.0          
## [10] colorspace_1.4-1    raster_3.1-5        withr_2.3.0        
## [13] sp_1.4-5            tidyselect_1.1.0    gridExtra_2.3      
## [16] prettyunits_1.1.1   leaflet_2.0.3       curl_4.3           
## [19] compiler_4.0.2      extrafontdb_1.0     cli_2.3.1          
## [22] leafem_0.1.1        scales_1.1.1        classInt_0.4-3     
## [25] systemfonts_0.2.1   digest_0.6.27       rmarkdown_2.6.4    
## [28] svglite_1.2.3       base64enc_0.1-3     dichromat_2.0-0    
## [31] jpeg_0.1-8.1        pkgconfig_2.0.3     htmltools_0.5.1.1  
## [34] extrafont_0.17      highr_0.8           htmlwidgets_1.5.1  
## [37] rlang_0.4.10        rstudioapi_0.13     generics_0.1.0     
## [40] farver_2.0.3        crosstalk_1.1.0.1   magrittr_2.0.1     
## [43] Rcpp_1.0.6          munsell_0.5.0       abind_1.4-5        
## [46] gdtools_0.2.2       lifecycle_0.2.0     stringi_1.5.3      
## [49] leafsync_0.1.0      yaml_2.2.1          tmaptools_3.0      
## [52] geogrid_0.1.1       grid_4.0.2          parallel_4.0.2     
## [55] ggrepel_0.8.2       crayon_1.4.1        lattice_0.20-41    
## [58] stars_0.4-1         hms_0.5.3           knitr_1.31         
## [61] pillar_1.4.7        codetools_0.2-16    imguR_1.0.3        
## [64] XML_3.99-0.3        glue_1.4.2          evaluate_0.14      
## [67] gifski_0.8.6        png_0.1-7           vctrs_0.3.6        
## [70] tweenr_1.0.1        Rttf2pt1_1.3.8      gtable_0.3.0       
## [73] purrr_0.3.4         assertthat_0.2.1    xfun_0.22          
## [76] lwgeom_0.2-3        e1071_1.7-4         rnaturalearth_0.1.0
## [79] class_7.3-17        viridisLite_0.3.0   tibble_3.0.4       
## [82] units_0.6-7         ellipsis_0.3.1
 

A work by Michal Michalski

 

LS0tCnRpdGxlOiAiQ09WSUQtMTkgYW5hbHlzaXMgYW5kIG1hcHBpbmciCmF1dGhvcjogIk1pY2hhbCBNaWNoYWxza2kiCmRhdGU6ICIxNC8xMi8yMDIwIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIAotLS0KPHN0eWxlPgpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I0QzRDNEMzsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJibHVlIj4KU29tZSBwZXJzb25hbCBhbmQgY29tcHV0YXRpb25hbCBub3RlcyBsb29zZWx5IGJhc2VkIG9uIHRoZSBhbmFseXRpY2FsIHdvcmsgSSBoYXZlIGRvbmUgaW4gcmVzcG9uc2UgdG8gQ09WSUQtMTkgcGFuZGVtaWMgaW4gU2NvdGxhbmQuCkluIG15IEdJUyBBbmFseXN0IHJvbGUgSSB1c2Ugd2lkZSByYW5nZSBvZiBwcm9wcmlldGFyeSBhbmQgb3BlbiBzb3VyY2UgR0lTIHNvZnR3YXJlIGFzIHdlbGwgYXMgdGVuZCB0byBibGVuZCBSIGFuZCBQeXRob24gbGFuZ3VhZ2VzLiAKSGVyZSBpcyBhIGZsYXZvciBvZiBteSB3b3JrIGluIG9wZW4gYW5kIHJlcHJvZHVjaWJsZSBub3RlYm9vaywgZm9sbG93aW5nIGEgRG9uYWxkIEtudXRoJ3MgImxpdGVyYXRlIHByb2dyYW1taW5nIiBwYXJhZGlnbS4KPC9kaXY+CgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIyBQYWNrYWdlcwoKRmlyc3QsYWxsIHBhY2thZ2VzIG5lY2Vzc2FyeSBmb3IgdGhlIGFuYWx5c2lzLgpgYGB7ciBwYWNrYWdlcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkoc2YpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoZ2doaWdobGlnaHQpCmxpYnJhcnkoaHJicnRoZW1lcykKbGlicmFyeShnZ2FuaW1hdGUpICMgYW5pbWF0ZSBwbG90cwpsaWJyYXJ5KGdlb2ZhY2V0KQpsaWJyYXJ5KHpvbykgIyBtb3ZpbmcgYXZhcmFnZXMKYGBgCgojIyBEYXRhIFdyYW5nbGluZwoKTm93LCBsZXRzIHJlYWQgdGhlIGRhdGEgZnJvbSB0aGUgKkRhdGEgU2NpZW5jZSBTY290bGFuZCogcmVwb3NpdG9yeQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9CmNhc2VzX3Njb3QgPSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0RhdGFTY2llbmNlU2NvdGxhbmQvQ09WSUQtMTktTWFuYWdlbWVudC1JbmZvcm1hdGlvbi9tYXN0ZXIvQ09WSUQxOSUyMC0lMjBEYWlseSUyME1hbmFnZW1lbnQlMjBJbmZvcm1hdGlvbiUyMC0lMjBTY290bGFuZCUyMC0lMjBUZXN0aW5nLmNzdiIpICU+JSAKICBzZWxlY3QoRGF0ZSwnVGVzdGluZyAtIEN1bXVsYXRpdmUgcGVvcGxlIHRlc3RlZCBmb3IgQ09WSUQtMTkgLSBQb3NpdGl2ZScpICU+JSAKICByZW5hbWUodG90YWwgPSAnVGVzdGluZyAtIEN1bXVsYXRpdmUgcGVvcGxlIHRlc3RlZCBmb3IgQ09WSUQtMTkgLSBQb3NpdGl2ZScpICU+JSAKICBtdXRhdGUoZGF0ZSA9IGFzLkRhdGUoRGF0ZSwgIiVkLSViLSVZIikpCiAgCgojIGRlYXRocyAKZGVhdGhzX3Njb3QgPSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0RhdGFTY2llbmNlU2NvdGxhbmQvQ09WSUQtMTktTWFuYWdlbWVudC1JbmZvcm1hdGlvbi9tYXN0ZXIvQ09WSUQxOSUyMC0lMjBEYWlseSUyME1hbmFnZW1lbnQlMjBJbmZvcm1hdGlvbiUyMC0lMjBTY290bGFuZCUyMC0lMjBEZWF0aHMuY3N2IikgJT4lIAogICAgcmVuYW1lKHRvdGFsID0gJ051bWJlciBvZiBDT1ZJRC0xOSBjb25maXJtZWQgZGVhdGhzIHJlZ2lzdGVyZWQgdG8gZGF0ZScpICU+JSAKICAgIG11dGF0ZShkYXRlID0gYXMuRGF0ZShEYXRlLCAiJWQtJWItJVkiKSkKCmBgYAoKU2luY2Ugd2Ugb25seSBoYXZlIG9uIHZhcmlhYmxlIHdpdGggdG90YWwgY2FzZXMgYW5kIGRlYXRocywgd2UgYXJlIGdvaW5nIHRvIGNhbGN1bGF0ZSBhZGRpdGlvbmFsIGF0dHJpYnV0ZXM6IApkYWlseSBuZXcgY2FzZXMsIHBlcmNlbnRhZ2UgY2hhbmdlIGFuZCBzZXZlbiBkYXlzIHJvbGxpbmcgYXZlcmFnZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQoKI2Nhc2VzIApjYXNlc19zY290ICA9IGNhc2VzX3Njb3QgICU+JSAKbXV0YXRlKG5ld19jYXNlcyA9ICh0b3RhbCAtIGxhZyh0b3RhbCkpLCAjIG5ldyBkYWlseSBjYXNlcyAKICAgICAgIHBjdF9jaGFuZ2UgPSBuZXdfY2FzZXMgLyBsYWcodG90YWwpICogMTAwLCAjIHBlcmNlbnRhZ2UgY2hhbmdlCiAgICAgICBjYXNlc18wN2RhID0gcm9sbG1lYW4obmV3X2Nhc2VzLCBrID0gNywgZmlsbCA9IE5BKSkgIyA3IGRheXMgcm9sbGluZyBhdmVyYWdlCgoKCiMgZGVhdGhzCmRlYXRoc19zY290ICA9IGRlYXRoc19zY290ICAlPiUgCm11dGF0ZShuZXdfZGVhdGhzID0gKHRvdGFsIC0gbGFnKHRvdGFsKSksICMgbmV3IGRhaWx5IGNhc2VzIAogICAgICBwY3RfY2hhbmdlID0gbmV3X2RlYXRocyAvIGxhZyh0b3RhbCkgKiAxMDAsICMgcGVyY2VudGFnZSBjaGFuZ2UKICAgICAgZGVhdGhzXzA3ZGEgPSByb2xsbWVhbihuZXdfZGVhdGhzLCBrID0gNywgZmlsbCA9IE5BKSkgIyA3IGRheXMgcm9sbGluZyBhdmVyYWdlCgoKYGBgCgojIyBQbG90dGluZwoKV2UgYXJlIHJlYWR5IHRvIHBsb3Qgb3VyIHZhcmlhYmxlcyB1c2luZyAqKmdncGxvdCoqIHBhY2thZ2UKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQoKZ2dwbG90KCkrCiAgZ2VvbV9saW5lKGRhdGEgPSBjYXNlc19zY290LCBhZXMoeD1EYXRlLCB5PW5ld19jYXNlcyksIGNvbG9yPSdncmF5JykgKwogIGdlb21fbGluZShkYXRhID0gY2FzZXNfc2NvdCwgYWVzKHg9RGF0ZSwgeT1jYXNlc18wN2RhKSwgY29sb3I9JyNiYTAwMDAnKSArCiAgbGFicyggdGl0bGUgPSAiU2NvdGxhbmQncyA3IGRheXMgcm9sbGluZyBhdmVyYWdlIENPVklELTE5IGNhc2VzIiwKICAgICAgICBzdWJ0aXRsZSA9ICJCZXR3ZWVuIE1hcmNoIDIwMjAgYW5kIE1hcmNoIDIwMjEiLCAKICAgICAgICBjYXB0aW9uPSJTb3VyY2U6aHR0cHM6Ly9naXRodWIuY29tL0RhdGFTY2llbmNlU2NvdGxhbmQvQ09WSUQtMTktTWFuYWdlbWVudC1JbmZvcm1hdGlvbiAiLAogICAgICAgIHkgPSAiQ2FzZXMiLCAKICAgICAgICB4ID0gIk1vbnRoIikgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICcxIG1vbnRoJywgZGF0ZV9sYWJlbHMgPSAnJW0gJXknKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICBocmJydGhlbWVzOjp0aGVtZV9pcHN1bSgpCmBgYAoKIyMgTWFwcGluZwoKV2UgY2FuIGFsc28gY3JlYXRlIGEgbWFwIHNob3dpbmcgbGF0ZXN0IGNhc2VzIGF0IE5IUyBIZWFsdGggQm9hcmQgbGV2ZWwuCkJ1dCBmaXJzdCB3ZSBuZWVkIHRvIGdldCB0aGUgZGF0YSBmb3IgZWFjaCBnZW9ncmFwaCB1bml0LgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9CiMgbG9hZCBkYXRhCmNhc2VzX2J5X2hiID0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9EYXRhU2NpZW5jZVNjb3RsYW5kL0NPVklELTE5LU1hbmFnZW1lbnQtSW5mb3JtYXRpb24vbWFzdGVyL0NPVklEMTklMjAtJTIwRGFpbHklMjBNYW5hZ2VtZW50JTIwSW5mb3JtYXRpb24lMjAtJTIwU2NvdHRpc2glMjBIZWFsdGglMjBCb2FyZHMlMjAtJTIwQ3VtdWxhdGl2ZSUyMGNhc2VzLmNzdiIpCgojIHBpdm90IGRhdGEgdG8gbG9uZyBmb3JtYXQgbmQgc2VsZWN0IGxhdGVzdCBkYXRlCmxhc3RfY2FzZXNfYnlfaGJfbG9uZyA9IGNhc2VzX2J5X2hiICU+JQpwaXZvdF9sb25nZXIoIURhdGUsbmFtZXNfdG8gPSAiaGJfbmFtZSIsIHZhbHVlc190byA9ICJjYXNlcyIpICAlPiUKbXV0YXRlKGNhc2VzID0gYXMubnVtZXJpYyhjYXNlcykpICU+JSAKZmlsdGVyKERhdGUgPT0gbWF4KERhdGUpKQoKIyBsb2FkIG1pZCAyMDE5IHBvcHVsYXRpb24gZXN0aW1hdGllCnBvcF9oYiA9IHJlYWRfY3N2KCJkYXRhL2hiX3BvcF8yMDE5LmNzdiIpCgojIGZpcnN0IGpvaW46IGNhc2VzIHdpdGggcG9wdWxhdGlvbiwgYWxzbyBjYWxjdWxhdGUgcmF0ZSBwZXIgMTAwawpjYXNlc19ieV9oYl9wb3AgPSBsZWZ0X2pvaW4obGFzdF9jYXNlc19ieV9oYl9sb25nLCBwb3BfaGIpICU+JSAKICBtdXRhdGUoCiAgICByYXRlXzEwMGsgPSBjYXNlcyAvIGhiX3BvcCAqIDEwMDAwMAogICkKCiMgbG9hZCBIZWFsdGggQm9hcmQgZ2VvZ3JhcGhpZXMKaGVhbHRoX2JvYXJkcyA9IHN0X3JlYWQoImRhdGEvU0dfTkhTX0hlYWx0aEJvYXJkc18yMDE5LnNocCIsIHF1aWV0ID0gVFJVRSkKCiMgc2Vjb25kIGpvaW46IGhlYWx0aCBib2FyZCBib3VuZGFyaWVzIApjYXNlc19oYl9yYXRlMTAwayA9IGxlZnRfam9pbihoZWFsdGhfYm9hcmRzLGNhc2VzX2J5X2hiX3BvcCwgYnkgPSBjKCJIQkNvZGUiID0gImhiX2NvZGUiKSkKCgpgYGAKCkZpbmFsbHksIHdlIGFyZSByZWFkeSB0byBwcm9kdWNlIHRoZSBtYXAgdXNpbmcgKip0bWFwKiogcGFja2FnZS4gCk5vdGUgdGhhdCB3ZSBhcmUgc2F2aW5nIHRoZSBvdXRwdXQgdG8gcG5nIGZpbGUuCgpgYGB7cn0KCm1hcCA9IHRtX3NoYXBlKGNhc2VzX2hiX3JhdGUxMDBrKSArCiAgdG1fcG9seWdvbnMoY29sID0gInJhdGVfMTAwayIsCiAgICAgICAgICAgICAgdGl0bGUgPSAiRGF0YSBmcm9tIDE3dGggTWFyY2ggMjAyMSBcbk51bWJlciBvZiBjb25maXJtZWQgY2FzZXMgcGVyIDEwMCwwMDAgcGVvcGxlIiwKICAgICAgICAgICAgICBsd2QgPSAxLAogICAgICAgICAgICAgIGJvcmRlci5jb2wgPSAid2hpdGUiLAogICAgICAgICAgICAgIHN0eWxlID0gImVxdWFsIiwKICAgICAgICAgICAgICBuID0gNSwKICAgICAgICAgICAgICBwYWxldHRlPSJjaXZpZGlzIiAjIGNob29zZSBiZXR3ZWVuIHJlZHMgb3IgY2l2aWRpcwogICAgICAgICAgICAgIyBsZWdlbmQuZm9ybWF0PWxpc3QoZnVuPWZ1bmN0aW9uKHgpIHBhc3RlMChmb3JtYXRDKHgsIGRpZ2l0cz0wLCBmb3JtYXQ9ImYiKSkpCiAgICAgICAgICAgICAgKSArCiAgdG1fbGF5b3V0KAogICAgICAgICAgICMgZm9udGZhbWlseSA9ICJhcmlhbCIsCiAgICAgICAgICAgIHRpdGxlID0gIlRvdGFsIENPVklEIC0gMTkgY2FzZXMgXG5wZXIgMTAwLDAwMCBwZW9wbGUsIGJ5IE5IUyBIZWFsdGggQm9hcmQiLAogICAgICAgICAgICB0aXRsZS5zaXplID0gMC45LAogICAgICAgICAgICBsZWdlbmQudGl0bGUuc2l6ZSA9IDEsCiAgICAgICAgICAgIGF0dHIub3V0c2lkZT0gVFJVRSwKICAgICAgICAgICAgYXR0ci5vdXRzaWRlLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgIGF0dHIub3V0c2lkZS5zaXplID0gLjEsCiAgICAgICAgICAgIGF0dHIuanVzdCA9IGMoImxlZnQiLCAidG9wIiksCiAgICAgICAgICAgIGlubmVyLm1hcmdpbnMgPSAwLjAyLAogICAgICAgICAgICBvdXRlci5tYXJnaW5zID0gYygwLDAuMDEsMC4wMSwwLjAxKSwKICAgICAgICAgICAgYXNwID0gNC82LAogICAgICAgICAgICBmcmFtZSA9IEYsCiAgICAgICAgICAgIGRlc2lnbi5tb2RlID0gRgogICAgICAgICAgICkgKwogIHRtX2NyZWRpdHMoIkNhc2VzIGRhdGEgZnJvbTogaHR0cHM6Ly93d3cuZ292LnNjb3QvY29yb25hdmlydXMtY292aWQtMTlcblBvcHVsYXRpb24gZGF0YTogTlJTIFBvcHVsYXRpb24gRXN0aW1hdGVzLCBtaWQtMjAxOFxuQm91bmRhcmllczogU3BhdGlhbERhdGEuZ292LnNjb3QiLAogICAgICAgICAgICAgY29sID0gImdyZXk1MCIsCiAgICAgICAgICAgICBwb3NpdGlvbj1jKCJsZWZ0IiwidG9wIiksIAogICAgICAgICAgICAgYWxpZ24gPSAibGVmdCIsCiAgICAgICAgICAgICBzaXplID0gMC4zMjUpCiMgc2F2ZSBncmFwaGljIHRvIHBuZyBmaWxlCnRtYXBfc2F2ZSgKICB0bSA9IG1hcCwKICBmaWxlbmFtZSA9ICJoYl9tYXBfY2FzZXNfcmF0ZS5wbmciLAogIGhlaWdodCA9IDYsCiAgd2lkdGggPSA0LAogIHVuaXRzID0gImluIiwKICBhc3AgPSA0LzYKKQpgYGAKCk9rLCBtYXAgaXMgcmVhZHkgIQoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0gNjAwLCBmaWcuY2FwPSIiLCBmaWcuYWxpZ249J2xlZnQnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaGJfbWFwX2Nhc2VzX3JhdGUucG5nIikKYGBgCgpJIGNhbid0IHJlY29tbWVuZCAqKnRtYXAqKiBwYWNrYWdlIGVub3VnaC4KCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IDYwMCwgZmlnLmNhcD0iIiwgZmlnLmFsaWduPSdsZWZ0J30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInRtYXBfYW5pbS5naWYiKQpgYGAKCiMjIFNlc3Npb24gaW5mbwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoKJm5ic3A7CjxociAvPgo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+QSB3b3JrIGJ5IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS90b3BvZ3JhcGhvcy8iPk1pY2hhbCBNaWNoYWxza2k8L2E+PC9wPgombmJzcDsK